﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
using Microsoft.WindowsAzure.ServiceRuntime;
using System.Diagnostics;
using System.Reflection;
using System.Data.Services.Client;

namespace PlatformWorkerRole
{
    public class TableServiceAPI
    {
        public CloudStorageAccount account;
        public CloudTableClient tableClient;
        public TableServiceContext context;

        public TableServiceAPI(string configSettingName)
        {
            account = CloudStorageAccount.FromConfigurationSetting(configSettingName);
            tableClient = account.CreateCloudTableClient();
            tableClient.RetryPolicy = RetryPolicies.Retry(4, TimeSpan.Zero);
            context = tableClient.GetDataServiceContext();
        }

        public bool ListTables(out List<string> tableList)
        {
            tableList = new List<string>();

            try
            {
                IEnumerable<string> tables = tableClient.ListTables();
                if (null != tables && tables.Count<string>() > 0)
                {
                    tableList.AddRange(tables);
                }
                return true;
            }
            catch (StorageClientException ex)
            {
                Trace.WriteLine(ex.Message);
                return false;
            }
        }

        public bool CreateTable(string tableName)
        {
            try
            {
                tableClient.CreateTable(tableName);
                return true;
            }
            catch (StorageClientException ex)
            {
                Trace.WriteLine(ex.Message);
                return false;
            }
        }

        public bool DropTable(string tableName)
        {
            try
            {
                tableClient.DeleteTableIfExist(tableName);
                return true;
            }
            catch (StorageClientException ex)
            {
                Trace.WriteLine(ex.Message);
                return false;
            }
        }

        public bool InsertEntity(string tableName, object entity)
        {
            try
            {
                context.AddObject(tableName, entity);
                context.SaveChanges();

                return true;
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message);
                return false;
            }
        }

        public bool DeleteEntity<T>(string tableName, string partitionKey, string rowKey) where T : TableServiceEntity
        {
            try 
            {
                IQueryable<T> entities = from e in context.CreateQuery<T>(tableName)
                                                          where e.PartitionKey == partitionKey && e.RowKey == rowKey
                                                          select e;
                if (null == entities)
                    return false;
                else
                {
                    context.DeleteObject(entities.FirstOrDefault<T>());
                    context.SaveChanges();

                    return true;
                }
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message);
                return false;
            }
        }

        public bool UpdateEntity<T>(string tableName, string partitionKey, string rowKey, T newEntity) where T : TableServiceEntity
        {
            try
            {
                IQueryable<T> entities = from e in context.CreateQuery<T>(tableName)
                                                          where e.PartitionKey == partitionKey && e.RowKey == rowKey
                                                          select e;
                if (null == entities)
                    return false;
                else
                {
                    T entity = entities.FirstOrDefault<T>();
                    Type t = newEntity.GetType();
                    foreach (PropertyInfo pi in t.GetProperties())
                    {
                        //Trace.WriteLine(String.Format("\t{0}", pi.GetValue(newEntity, null)));
                        pi.SetValue(entity, pi.GetValue(newEntity, null), null);
                    }

                    context.UpdateObject(entity);
                    context.SaveChanges();

                    return true;
                }
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message);
                return false;
            }
        }

        public bool GetEntity<T>(string tableName, string partitionKey, string rowKey, out T entity) where T : TableServiceEntity
        {
            entity = null;

            try
            {
                IQueryable<T> entities = from e in context.CreateQuery<T>(tableName)
                                                          where e.PartitionKey == partitionKey && e.RowKey == rowKey
                                                          select e;
                if (null == entities)
                    return false;
                else 
                {
                    entity = entities.FirstOrDefault<T>();
                    return true;
                }
            }
            catch (Exception ex)
            {
                Trace.WriteLine(String.Format("Exception: {0}", ex.Message));
                return false;
            }
        }

        public DataServiceQuery<T> SelectEntities<T>(string tableName) where T : TableServiceEntity
        {
            return context.CreateQuery<T>(tableName);
        }
    }
}
